package com.google.code.swingonfire.utility;

/**
 * A default scanner
 * 
 * @author thred
 */
public class Scanner
{

    public static final char END_OF_SOURCE = 0;

    private final char[] source;
    private final int endOffset;

    private int offset = 0;
    private int line = 1;
    private int column = 1;

    private char lookAhead = END_OF_SOURCE;
    private char ch = END_OF_SOURCE;

    /**
     * Creates a new scanner
     * 
     * @param source the source
     */
    public Scanner(char[] source)
    {
        this(1, 1, source, 0, source.length);
    }

    /**
     * Creates a new scanner
     * 
     * @param source the source
     * @param offset the offset where to start
     * @param length the length, when reached c is END_OF_CODE, if length < 0 it will be set the end of the array
     */
    public Scanner(char[] source, int offset, int length)
    {
        this(1, 1, source, offset, length);
    }

    /**
     * Creates a new scanner
     * 
     * @param line the line where to start counting, this is usually 1 (not zero)
     * @param column the column where to start counting, this is usually 1 (not zero)
     * @param source the source
     * @param offset the offset where to start
     * @param length the length, when reached c is END_OF_CODE, if length < 0 it will be set the end of the array
     */
    public Scanner(int line, int column, char[] source, int offset, int length)
    {
        super();

        this.line = line;
        this.column = column;

        this.source = source;
        this.offset = offset;
        endOffset = (length < 0) ? source.length : offset + length;

        lookAhead = ((offset + 1) < endOffset) ? source[offset + 1] : END_OF_SOURCE;
        ch = (offset < endOffset) ? source[offset] : END_OF_SOURCE;
    }

    public int getOffset()
    {
        return offset;
    }

    public int getLine()
    {
        return line;
    }

    public int getColumn()
    {
        return column;
    }

    public char getLookAhead()
    {
        return lookAhead;
    }

    public char getChar()
    {
        return ch;
    }

    public char next()
    {
        if ((ch == '\n') || ((ch == '\r') && (lookAhead != '\n')))
        {
            line += 1;
            column = 1;
        }
        else
        {
            column += 1;
        }

        offset += 1;

        ch = lookAhead;

        lookAhead = ((offset + 1) < endOffset) ? source[offset + 1] : END_OF_SOURCE;

        return ch;
    }

    public boolean skipWhitespaces()
    {
        boolean result = false;

        while (isWhitespace())
        {
            result |= (ch == '\r') || (ch == '\n');

            next();
        }

        return result;
    }

    private boolean isWhitespace()
    {
        return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
    }

    public boolean skip(int amount)
    {
        boolean result = false;

        for (int i = 0; i < amount; i += 1)
        {
            if (next() == END_OF_SOURCE)
            {
                break;
            }

            result |= (ch == '\r') || (ch == '\n');
        }

        return result;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString()
    {
        return new String(source);
    }

}